﻿using Engine;
using Game;
using Game.Server.Event;
using Game.Server.PlayerEvent;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using System;
using Game.NetWork.Packages;
using Game.NetWork;
using System.Text;
using System.Security.Cryptography;
using LiteNetLib;
using TemplatesDatabase;
using Engine.Graphics;
using GameEntitySystem;

namespace Game.Server.Plugins
{
    /// <summary>
    /// 插件指令
    /// </summary>
    public class CmdDeathMatch : AbstractProcessCmd
    {
        public override string Cmd => "de"; //指令名

        public override string Introduce => "/" + Cmd + "    -查看死亡竞赛的命令帮助"; //指令说明

        public override int AuthLevel => 0; //指令权限等级

        public override DisplayType Display => DisplayType.Authority; //指令是否可查看

        public const string Title = "deathMatch";
        public Random m_random = new Random();
        private void SendHelpMessage()
        {
            string message = "\n" +
                "/de back    -回到初始复活点\n" +
                "/de respawn    -加入战斗\n" +
                "/de score    -查看自己的得分\n" +
                "/de ranking    -查看玩家得分排行榜\n" +
                "/de help    -显示更多关于死亡竞赛模式的介绍";
            SendMessage(Title, message);
        }
        //吸烟室：102, 71, 88
        //中立区域：50, 64, 30; 130, 64, 110
        //100, 253, -100
        public static void FindPlayersByName(string name, Action<ComponentPlayer> action)
        {
            if (GameManager.Project != null)
            {
                var playersData = GameManager.Project.FindSubsystem<SubsystemPlayers>().PlayersData;
                foreach (var player in playersData)
                {
                    if (player.Name == name)
                    {
						action?.Invoke(player.ComponentPlayer);
					}
                }
            }

        }
        public override void Process(string username, NetNode netNode, Client client, string[] messageDatas, bool isTerminal = false)
        {
            //if (!isTerminal)
            //    return;
            m_username = username;
            m_netNode = netNode;
            m_client = client;
            m_messageDatas = messageDatas;
            m_isTerminal = isTerminal;
            for (int i = 0; i < m_messageDatas.Length; i++)
            {
                m_messageDatas[i] = m_messageDatas[i].ToLower();
            }
            if (m_messageDatas.Length <= 1)
            {
                SendHelpMessage();
            }
            else
            {
                string c = m_messageDatas[1];
                if (c == "back")
                {
                    FindPlayersByName(username, delegate (ComponentPlayer componentPlayer)
                    {
                        if (DeathMatchPlugin.PlayerScore.ContainsKey(componentPlayer.PlayerData.Name))
                            DeathMatchPlugin.PlayerScore[componentPlayer.PlayerData.Name] = 0;
                        componentPlayer.ComponentBody.Position = new Vector3(DeathMatchPlugin.BackPosition) + Vector3.UnitY;
                        foreach (IInventory inventory in componentPlayer.Entity.FindComponents<IInventory>())
                        {//重置装备
                            inventory.DropAllItems(Vector3.Zero);
                            //for (int index = 0; index < inventory1.SlotsCount; index++)
                            //{
                            //    inventory1.RemoveSlotItems(index, inventory1.GetSlotCount(index));
                            //    break;
                            //}
                        }
                        CommonLib.Net.QueuePackage(new ComponentPlayerPackage(componentPlayer, ComponentPlayerPackage.PlayerAction.PositionSet));
                        SendMessage(Title, "你已通过指令回城");
                    });
					Log.Information("玩家\"" + username + "\"使用了回城指令");
				}
                else if (c == "respawn" || c == "r")
                {
                    FindPlayersByName(username, delegate (ComponentPlayer componentPlayer)
                    {
						if (DeathMatchPlugin.IsInNeutralArea(componentPlayer.ComponentBody.Position.XZ))
						{
                            foreach(IInventory inventory in componentPlayer.Entity.FindComponents<IInventory>())
                            {//重置装备
                                inventory.DropAllItems(Vector3.Zero);
                                //for (int index = 0; index < inventory.SlotsCount; index++)
                                //{
                                //    inventory.RemoveSlotItems(index, inventory.GetSlotCount(index));
                                //    break;
                                //}
                            }
                            //给新装备
                            var componentInventory = componentPlayer.Entity.FindComponent<ComponentInventory>();
                            int outfitId;
                            if (m_messageDatas.Length >= 3 && int.TryParse(m_messageDatas[2], out int num))
							{
                                if(num >= 0 && num < DeathMatchPlugin.OutfitPresets.Count)
                                    outfitId = num;
                                else
                                {
                                    outfitId = m_random.Int(0, DeathMatchPlugin.OutfitPresets.Count - 1);
                                    SendMessage(Title, "未知的预设id！已随机分配出场装备");
                                }
                            }
                            else
                                outfitId = m_random.Int(0, DeathMatchPlugin.OutfitPresets.Count - 1);
                            List<ComponentInventoryBase.Slot> items = DeathMatchPlugin.OutfitPresets[outfitId];
                            foreach(var slot in items)
							{
                                //int itemValue = 492126, itemCount = 1;
                                int itemValue = slot.Value, itemCount = slot.Count;
                                for (int index = 0; index < componentInventory.SlotsCount; index++)
                                {
                                    int slotValue = componentInventory.GetSlotValue(index);
                                    int slotCount = componentInventory.GetSlotCount(index);
                                    int slotCapacity = componentInventory.GetSlotCapacity(index, itemValue);
                                    if ((slotCount != 0 && slotValue != itemValue) || slotCount + itemCount > slotCapacity)
                                    {
                                        continue;
                                    }
                                    Block block = BlocksManager.Blocks[Terrain.ExtractContents(itemValue)];
                                    if (block is ClothingBlock)
                                    {//自动穿上衣服
                                        ClothingData clothingData = BlocksManager.Blocks[Terrain.ExtractContents(itemValue)].GetClothingData(Terrain.ExtractData(itemValue));
                                        var list = new List<int>(componentPlayer.ComponentClothing.GetClothes(clothingData.Slot)) { itemValue };
                                        componentPlayer.ComponentClothing.SetClothes(clothingData.Slot, list);
                                        componentPlayer.ComponentClothing.OnSlotChange((int)clothingData.Slot);
                                    }
                                    else
                                        componentInventory.AddSlotItems(index, itemValue, itemCount);
                                    break;
                                }
                            }
                            //5秒无敌
                            DeathMatchPlugin.AddInvulnerablePlayer(username, Time.FrameStartTime + 5);
                            //随机传送
                            Point3 position = DeathMatchPlugin.RespawnSites[m_random.Int(0, DeathMatchPlugin.RespawnSites.Count - 1)];
                            componentPlayer.ComponentBody.Position = new Vector3(position) + Vector3.UnitY;
                            CommonLib.Net.QueuePackage(new ComponentPlayerPackage(componentPlayer, ComponentPlayerPackage.PlayerAction.PositionSet));
                            //变成满级
                            componentPlayer.PlayerData.Level = 25;
                            CommonLib.Net.QueuePackage(new ComponentPlayerPackage(componentPlayer.PlayerData, 1, false, 25));
                            SendMessage(Title, "已加入战斗！你有5秒的准备时间，抓紧机会");
                        }
                        else
                            SendMessage(Title, "你不在中立区域，无法使用重生指令");
                    });
                }
                else if (c == "score")
                {
                    FindPlayersByName(username, delegate (ComponentPlayer componentPlayer)
                    {
                        int score = 0;
                        if (DeathMatchPlugin.PlayerScore.TryGetValue(componentPlayer.PlayerData.Name, out int value))
                            score = value;
                        SendMessage(Title, "你的分数：" + score.ToString());
                    });
                }
                else if (c == "ranking")
                {
                    FindPlayersByName(username, delegate (ComponentPlayer componentPlayer)
                    {
                        string msg = "死亡竞赛 玩家排行榜Top5：\n";
                        if (DeathMatchPlugin.PlayerScore.Count <= 0)
                            msg += "暂无数据";
						else
						{
                            var list = DeathMatchPlugin.PlayerScore.ToDynamicArray().ToList();
                            list.Sort((pair1, pair2) => pair2.Value.CompareTo(pair1.Value));
                            int num = 0;
                            foreach (var item in list)
                            {
                                num++;
                                msg += "No." + num.ToString() + "  " + item.Key + "  " + item.Value.ToString() + "\n";
                                if (num >= 5)
                                    break;
                            }
                        }
                        SendMessage(Title, msg);
                    });
                }
                //else if (c == "invu" && m_messageDatas.Length >= 3)
                //{//测试，给输入指令的玩家赋予金身时间
                //    float time;
                //    try
                //    {
                //        time = float.Parse(m_messageDatas[2]);
                //    }
                //    catch
                //    {
                //        SendMessage(Title, "输入的数字格式不正确");
                //        return;
                //    }
                //    DeathMatchPlugin.AddInvulnerablePlayer(username, Time.FrameStartTime + (double)time);
                //    SendMessage(Title, "玩家\"" + username + "\"已获得" + time.ToString() + "秒金身时间");
                //}
                else
                    ProcessCmd();
            }

        }

        /// <summary>
        /// 指令执行
        /// </summary>
        public override void ProcessCmd()
        {
			//test txt根据空格分隔，第一个m_messageDatas[0]=test, 第二个m_messageDatas[1]=txt
			if (m_messageDatas[1] == "help")
			{
				string message = "插件_死亡竞赛  帮助：\n" +
					"死亡竞赛是一种快节奏的pvp战斗模式\n" +
					"在这里你只需要享受杀死其他玩家的快感\n" +
					"通常初始复活点附件会设定中立区域，无法攻击任何目标\n" +
                    "你需要使用指令投身战场\n" +
                    "装备弹药都由系统配给，无需担心消耗过快\n" +
                    "死亡后回到初始复活点，但可立即回到战斗\n" +
                    "每隔一段时间，地图中所有掉落物都会被清理\n" +
                    "杀死其他玩家可获得分数。你能否在排行榜上争得一席？";
				SendMessage(Title, message);
			}
		}
    }

    /// <summary>
    /// 插件服务
    /// </summary>
    public class DeathMatchPlugin : ServerPlugin, ICreatureSpawnEventHandle, ICreatureHealthEventHandle, IPlayerEnterGameEventHandle
    {
        public override int Version => 10000; //版本号

        public override string Name => "插件_死亡竞赛"; //插件名

        public byte FirstLevel => 0; //优先级

        private static readonly string PluginFolderPath = Directory.GetCurrentDirectory() + "/Plugins";

        public static void LoadConfig()
        {//加载配置
            string filePath1 = PluginFolderPath + "/NeutralArea.txt";
            if (File.Exists(filePath1))
            {
                using (StreamReader file = File.OpenText(filePath1))
                {
                    try
                    {
                        for (int i = 0; i < 2; i++)
                        {
                            string line = file.ReadLine();
                            string[] array = line.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            if (array.Length >= 2)
                            {
                                Point2 point = new Point2(int.Parse(array[0]), int.Parse(array[1]));
                                NeutralArea[i] = point;
                            }
                        }
                    }
                    catch
                    {
                        Log.Error("中立区域NeutralArea数据格式化错误，请重新进行设置");
                        return;
                    }
                    file.Close();
                    Log.Warning("中立区域NeutralArea数据加载成功");
                }
            }
            else
            {
                NeutralArea = new Point2[2] { Point2.Zero, Point2.One };
                WriteTxt(filePath1, "0,0\n1,1");
                Log.Warning("没有找到中立区域NeutralArea数据，因此新建了一个默认配置");
            }
            string filePath2 = PluginFolderPath + "/BackPosition.txt";
            if (File.Exists(filePath2))
            {
                using (StreamReader file = File.OpenText(filePath2))
                {
                    try
                    {
                        string line = file.ReadLine();
                        string[] array = line.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        if (array.Length >= 3)
                        {
                            Point3 point = new Point3(int.Parse(array[0]), int.Parse(array[1]), int.Parse(array[2]));
                            BackPosition = point;
                        }
                    }
                    catch
                    {
                        Log.Error("回城位置BackPosition数据格式化错误，请重新进行设置");
                        return;
                    }
                    file.Close();
                    Log.Warning("回城位置BackPosition数据加载成功");
                }
            }
            else
            {
                BackPosition = new Point3(0, 64, 0);
                WriteTxt(filePath2, "0,64,0");
                Log.Warning("没有找到回城位置BackPosition数据，因此新建了一个默认配置");
            }
            string filePath3 = PluginFolderPath + "/RespawnSites.txt";
            if (File.Exists(filePath3))
            {
                using (StreamReader file = File.OpenText(filePath3))
                {
                    try
                    {
                        string line;
                        while ((line = file.ReadLine()) != null)
                        {
                            string[] array = line.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            if (array.Length >= 3)
                            {
                                Point3 point = new Point3(int.Parse(array[0]), int.Parse(array[1]), int.Parse(array[2]));
                                RespawnSites.Add(point);
                            }
                        }
                    }
                    catch
                    {
                        Log.Error("复活点位RespawnSites数据格式化错误，请重新进行设置");
                        return;
                    }
                    file.Close();
                    Log.Warning("复活点位RespawnSites数据加载成功");
                }
            }
            else
            {
                RespawnSites.Add(new Point3(0, 64, 0));
                RespawnSites.Add(new Point3(1, 64, 1));
                WriteTxt(filePath3, "0,64,0\n1,64,1");
                Log.Warning("没有找到复活点位RespawnSites数据，因此新建了一个默认配置");
            }
            string filePath4 = PluginFolderPath + "/OutfitPresets.txt";
            string folderPath = PluginFolderPath + "/OutfitPresets";
            if (Directory.Exists(folderPath) == false)
            {
                Directory.CreateDirectory(folderPath);
            }
            if (File.Exists(filePath4))
            {
                using (StreamReader file = File.OpenText(filePath4))
                {
                    try
                    {
                        string line;
                        while ((line = file.ReadLine()) != null)
                        {
                            string filePath40 = PluginFolderPath + line;
							if (File.Exists(filePath40))
							{
                                List<ComponentInventoryBase.Slot> list = new List<ComponentInventoryBase.Slot>();
                                using (StreamReader file0 = File.OpenText(filePath40))
								{
                                    string line0;
                                    while ((line0 = file0.ReadLine()) != null)
                                    {
                                        string[] array = line0.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                        if (array.Length >= 2 && int.TryParse(array[0], out int value) && int.TryParse(array[1], out int count))
                                        {
                                            var slot = new ComponentInventoryBase.Slot() { Value = value, Count = count };
                                            list.Add(slot);
                                        }
                                    }
                                }
                                OutfitPresets.Add(list);
                            }
                        }
                    }
                    catch
                    {
                        Log.Error("装备预设OutfitPresets数据格式化错误，请重新进行设置");
                        return;
                    }
                    file.Close();
                    Log.Warning("装备预设OutfitPresets数据加载成功");
                }
            }
            else
            {
                List<ComponentInventoryBase.Slot> list = new List<ComponentInventoryBase.Slot>() { new ComponentInventoryBase.Slot() { Value = 74, Count = 1 } };
                OutfitPresets.Add(list);
                WriteTxt(filePath4, "/OutfitPresets/0.txt");
                WriteTxt(folderPath + "/0.txt", "74,1");
                Log.Warning("没有找到装备预设OutfitPresets数据，因此新建了一个默认配置");
            }
        }
        public static void WriteTxt(string path, string content)
        {
            FileStream filestream = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
            StreamWriter streamwriter = new StreamWriter(filestream);
            streamwriter.Write(content);
            streamwriter.Flush();
            streamwriter.Close();
            filestream.Close();
        }
        /// <summary>
        /// 加载插件时执行（初始化）
        /// </summary>
        public override void Initialize()
        {
            if (Directory.Exists(PluginFolderPath) == false)
            {
                Directory.CreateDirectory(PluginFolderPath);
            }
            LoadConfig();
            Log.Warning(Name + " 已完成初始化");
            CreatureSpawnEventManager.AddObject(this);
            CreatureHealthEventManager.AddObject(this);
            PlayerEnterGameEventManager.AddObject(this);
        }

        /// <summary>
        /// 存档加载时执行
        /// </summary>
        public override void Load()
        {
            //Log.Warning(Name + " 已加载配置：");
            InvulnerablePlayers.Clear();
        }

        /// <summary>
        /// 存档保存时执行
        /// </summary>
        public override void Save()
        {
            InvulnerablePlayers.Clear();
        }


        //生物生成事件接口
        public bool Update(SubsystemCreatureSpawn subsystemCreatureSpawn, float dt)
        {
            //         for(int i = 0;i < InvulnerablePlayers.Count;i++)
            //{
            //             string key = InvulnerablePlayers.Keys.ToDynamicArray()[i];
            //             float remainTime = InvulnerablePlayers[key];
            //             if (remainTime <= 0)
            //                 InvulnerablePlayers.Remove(key);
            //	else
            //	{
            //                 InvulnerablePlayers[key] = remainTime - dt;
            //	}
            //}
            if( subsystemCreatureSpawn.m_subsystemTime.PeriodicGameTimeEvent(10, 0))
			{//每隔一段时间清理一次掉落物
                SubsystemPickables subsystemPickables = subsystemCreatureSpawn.Project.FindSubsystem<SubsystemPickables>();
                if(subsystemPickables != null)
				{
                    foreach (Pickable pickable in subsystemPickables.m_pickables)
                        pickable.ToRemove = true;
                }
    //            var playersData = GameManager.Project.FindSubsystem<SubsystemPlayers>().PlayersData;
    //            var names = PlayerScore.Keys.ToDynamicArray();
    //            for(int i = 0; i < PlayerScore.Count;)
				//{
    //                string name = names[i];
    //                bool isPlayerExist = false;
    //                foreach (var player in playersData)
    //                {
    //                    if (player.Name == name)// && player.ComponentPlayer.IsAddedToProject)
    //                    {
    //                        isPlayerExist = true;
    //                        break;
    //                    }
    //                }
				//	if (!isPlayerExist)
				//	{
    //                    if (PlayerScore.ContainsKey(name))
    //                        PlayerScore.Remove(name);
    //                }
    //            }
            }

            return true;
        }

        public void OnEntityAdded(SubsystemCreatureSpawn subsystemCreatureSpawn, Entity entity)
        {

        }

        public void OnEntityRemoved(SubsystemCreatureSpawn subsystemCreatureSpawn, Entity entity)
        {
			ComponentPlayer componentPlayer = entity.FindComponent<ComponentPlayer>();
			if (componentPlayer != null)
			{
				string name = componentPlayer.PlayerData.Name;
				if (InvulnerablePlayers.ContainsKey(name))
					InvulnerablePlayers.Remove(name);
				//if (PlayerScore.ContainsKey(name))
				//	PlayerScore.Remove(name);
			}
		}

        public void OnPlayerSpawned(PlayerData playerData, Entity playerEntity, Vector3 position)
        {//这个貌似只有重生的时候才有用？
            //Log.Warning("1111");
            //Time.QueueTimeDelayedExecution(Time.FrameStartTime + 2.0, delegate
            //{
            //    ComponentGui componentGui = playerEntity.FindComponent<ComponentGui>();
            //    if (componentGui != null)
            //        componentGui.DisplaySmallMessage(playerData.Name + "; " + position.ToString(), Color.White, true, true);
            //});
        }

        public void InitCreatureTypes(SubsystemCreatureSpawn subsystemCreatureSpawn, List<SubsystemCreatureSpawn.CreatureType> creatureTypes) { }

        //生物Health事件接口
        public bool Heal(ComponentHealth componentHealth, float amount)
        {
            return true;
        }

        public bool Injure(ComponentHealth componentHealth, float amount, ComponentCreature attacker, string cause)
        {
            Vector2 position = componentHealth.m_componentCreature.ComponentBody.Position.XZ;
            if (IsInNeutralArea(position))
                return false;
            ComponentPlayer componentPlayer = componentHealth.Entity.FindComponent<ComponentPlayer>();
            if (componentPlayer != null)
            {
                if(InvulnerablePlayers.TryGetValue(componentPlayer.PlayerData.Name, out double endTime))
				{
                    if (endTime > Time.FrameStartTime)
                        return false;
                    else
                    {
                        InvulnerablePlayers.Remove(componentPlayer.PlayerData.Name);
                    }
                }
				if (attacker != null)
				{
					ComponentPlayer componentPlayer_attacker = attacker.Entity.FindComponent<ComponentPlayer>();
					if (componentPlayer_attacker != null && componentHealth.Health <= amount && componentHealth.Health > 0)
					{
						Score(componentPlayer_attacker);
					}
				}
			}
            return true;
        }

        public static void Score(ComponentPlayer componentPlayer)
		{//以后是否考虑加入判断不同武器得分？
            //int toolValue = componentPlayer.ComponentMiner.ActiveBlockValue;
            int score = 10;
			string name = componentPlayer.PlayerData.Name;
			if (PlayerScore.ContainsKey(name))
				PlayerScore[name] += score;
			else
				PlayerScore.Add(name, score);
			var messagePackget = new MessagePackage(CmdDeathMatch.Title, "成功击杀，获得10分数", 0, null)
			{
				To = componentPlayer.PlayerData.Client
			};
            Time.QueueTimeDelayedExecution(Time.FrameStartTime + 1.0, delegate
            {
                CommonLib.Net.QueuePackage(messagePackget);
            });
		}

        public static Dictionary<string, double> InvulnerablePlayers = new Dictionary<string, double>();
        public static void AddInvulnerablePlayer(string userName, double endTime)
        {
            if (InvulnerablePlayers.ContainsKey(userName))
                InvulnerablePlayers[userName] = endTime;
            else
                InvulnerablePlayers.Add(userName, endTime);
        }

        public static Point3 BackPosition = new Point3();
        public static Point2[] NeutralArea = new Point2[2];
        public static bool IsInNeutralArea(Vector2 position)
        {
            Vector2 min = new Vector2(NeutralArea[0]), max = new Vector2(NeutralArea[1]);
            return position.X >= min.X && position.Y >= min.Y && position.X <= max.X && position.Y <= max.Y;
        }
        public static Dictionary<string, int> PlayerScore = new Dictionary<string, int>();
        public static List<Point3> RespawnSites = new List<Point3>();
        public static List<List<ComponentInventoryBase.Slot>> OutfitPresets = new List<List<ComponentInventoryBase.Slot>>();

        //玩家进入游戏事件接口
        public void PlayerEnter(PlayerData playerData)
		{

		}

        public void PlayerLeave(PlayerData playerData)
		{
            string name = playerData.Name;
            if(PlayerScore.ContainsKey(name))
                PlayerScore.Remove(name);
		}

    }
}